FragmentPagerAdapterをほぼ無限スクロールに対応させる
はじめに
ViewPagerの無限スクロールは、色々な方がライブラリを提供しています。
しかし、PagerTabStripと併用できるものが見当たらないため、作成しました。
実装
InfiniteViewPager.java
public class InfiniteViewPager extends ViewPager { InfinitePagerAdapter mInfinitePagerAdapter; public InfiniteViewPager(Context context) { super(context); } public InfiniteViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public void setAdapter(PagerAdapter adapter) { mInfinitePagerAdapter = (InfinitePagerAdapter) adapter; super.setAdapter(adapter); setCurrentItem(0); // 初期表示位置 } @Override public void setCurrentItem(int item) { // 第2引数をtrueにする場合、 // アニメーションが不自然になるので、スクロールイベントでの対応が必要になる setCurrentItem(item, false); } @Override public void setCurrentItem(int item, boolean smoothScroll) { super.setCurrentItem( item % mInfinitePagerAdapter.getRealCount() + getOffsetAmount(), smoothScroll ); } @Override public int getCurrentItem() { // Viewの表示などで利用されるので、値を誤魔化す return super.getCurrentItem() % mInfinitePagerAdapter.getRealCount(); } private int getOffsetAmount() { // 開始位置を真ん中に近い数値にすることで、初期表示時に左へスクロールできるようにする // FIXME ページ数によっては、良い感じに調整してください。 return mInfinitePagerAdapter.getRealCount() * 100; } }
InfinitePagerAdapter.java
/** * 表示する各クラスで、実装を行えるようにする */ public abstract class InfinitePagerAdapter extends FragmentPagerAdapter { private int mRealCount = -1; public InfinitePagerAdapter(FragmentManager fm) { super(fm); } /** * 表示するフラグメントを実装する */ @Override public abstract Fragment getItem(int position); /** * 表示するタイトルを設定する */ @Override public abstract CharSequence getPageTitle(int position); @Override public int getCount() { // return Integer.MAX_VALUE を利用しているライブラリが多いですが、 // あまり大きすぎる値を設定すると、PagerTabStripと併用した際に // タブをクリックすると、フリーズしてしまう。 return 1000; } public void setRealCount(int count) { mRealCount = count; } public int getRealCount() { return mRealCount != -1 ? mRealCount : 0; } protected int convertToDummyPosition(int realPosition) { return realPosition % getRealCount(); } }
View側の実装(適宜良い感じに)
<com.sample.view.InfiniteViewPager android:id="@+id/sample_view_pager" android:layout_width="match_parent" android:layout_height="match_parent" > <android.support.v4.view.PagerTabStrip android:layout_width="match_parent" android:layout_height="wrap_content" /> </com.sample.view.InfiniteViewPager>
@Nullable @Override public View onCreateView(// 省略) { // 省略 InfinitePagerAdapter adapter = new SampleAdapter(getChildFragmentManager()); adapter.setRealCount(3); // 実際のページ数 mViewPager.setAdapter(adapter); // 省略 } // 実装クラス private static final class SampleAdapter extends InfinitePagerAdapter { public SampleAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return SampleFragment.newInstance(); } @Override public CharSequence getPageTitle(int position) { // 実際には大きな値がpositionに来るので // ダミー値に変換する switch (convertToDummyPosition(position)) { case 0: return "0番目タイトル"; case 1: return "1番目タイトル"; case 2: return "2番目タイトル"; default: return "error"; } } }
補足
今回の実装方法では、実質無限スクロールです。
getCountにて大きい値を設定し、getOffsetAmountで表示開始位置を真ん中に近い数値にしています。
その為、何回もスライドすれば限界まで到達します。
ダミーを両サイドに用意(C' A B C A')して、スクロールイベントで調整する方法もありますが
シンプルに実装できることと、PagerTabStrip・PagerTitleStripをそのまま導入できるので、ご紹介致しました。
あとがき
需要も多いので、公式で対応してくれると嬉しいのですが・・・
app:isLoop="true" と書くだけで出来るようになって欲しいですね(笑)